package com.example.tengoos.utils;

import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.model.*;
import com.qcloud.cos.transfer.TransferManager;
import com.qcloud.cos.transfer.TransferManagerConfiguration;
import com.qcloud.cos.transfer.Upload;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.example.tengoos.constants.TengOosConstans.*;

/**
 * @author 大忽悠
 * @create 2022/3/6 11:58
 */
@Slf4j
public class TengOosUtils {
    /**
     * 创建一个存储桶
     */
     public static Bucket createBucket(String bucketName)
     {
         CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
         // 设置 bucket 的权限为 Private(私有读写)、其他可选有 PublicRead（公有读私有写）、PublicReadWrite（公有读写）
         createBucketRequest.setCannedAcl(CannedAccessControlList.Private);
         try{
             return cosClient.createBucket(createBucketRequest);
         } catch (CosServiceException serverException) {
             serverException.printStackTrace();
         } catch (CosClientException clientException) {
             clientException.printStackTrace();
         }
         return null;
     }

    /**
     * 删除桶
     */
     public static void deleteBucket(String bucketName)
     {
         cosClient.deleteBucket(bucketName);
     }

    /**
     * 返回所有存储桶
     */
     public static List<Bucket> listBuckets()
     {
         return cosClient.listBuckets();
     }

    /**
     * 小文件上传---不超过5GB---最少小于20M--上传本地文件
     */
    public static PutObjectResult upLoadSmallFile(String localFilePath,String targetFilePath) {
        localFilePath=WINDOWS_FILE_UPLOAD+localFilePath;
        // 指定要上传
        File localFile = new File(localFilePath);
       // 指定文件上传到 COS 上的路径，即对象键。例如对象键为folder/picture.jpg，则表示将文件 picture.jpg 上传到 folder 路径下
        String key = targetFilePath;
        PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKETNAME, key, localFile);
        return cosClient.putObject(putObjectRequest);
    }

    /**
     * 将文件以二进制流形式上传到腾讯云上去保存
     */
    public static UploadResult upLoadFileStream(String fileKey,InputStream fileStream)
    {
        // 使用高级接口必须先保证本进程存在一个 TransferManager 实例，如果没有则创建
        TransferManager transferManager = createTransferManager();
        ObjectMetadata objectMetadata = new ObjectMetadata();
        PutObjectRequest putObjectRequest = new PutObjectRequest(BUCKETNAME, fileKey, fileStream, objectMetadata);
        try {
            // 高级接口会返回一个异步结果Upload
            // 可同步地调用 waitForUploadResult 方法等待上传完成，成功返回UploadResult, 失败抛出异常
            Upload upload = transferManager.upload(putObjectRequest);
            UploadResult uploadResult = upload.waitForUploadResult();
            return uploadResult;
        } catch (CosServiceException e) {
            e.printStackTrace();
        } catch (CosClientException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 列出某个桶下某个目录下面所有的文件
     */
    public static List<COSObjectSummary>  listObjects(String directoryPrefix)
    {
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
       // 设置bucket名称
        listObjectsRequest.setBucketName(BUCKETNAME);
       // prefix表示列出的object的key以prefix开始
        listObjectsRequest.setPrefix(directoryPrefix+"/");
       // deliter表示分隔符, 设置为/表示列出当前目录下的object, 设置为空表示列出所有的object
        listObjectsRequest.setDelimiter("/");
       // 设置最大遍历出多少个对象, 一次listobject最大支持1000
        listObjectsRequest.setMaxKeys(10);
        ObjectListing objectListing = null;
        List<COSObjectSummary> res=new ArrayList<>();
        do {
            try {
                objectListing = cosClient.listObjects(listObjectsRequest);
            } catch (CosServiceException e) {
                e.printStackTrace();
                return null;
            } catch (CosClientException e) {
                e.printStackTrace();
                return null;
            }
            // common prefix表示表示被delimiter截断的路径, 如delimter设置为/, common prefix则表示所有子目录的路径
            List<String> commonPrefixs = objectListing.getCommonPrefixes();

            // object summary表示所有列出的object列表
            List<COSObjectSummary> cosObjectSummaries = objectListing.getObjectSummaries();
            for (COSObjectSummary cosObjectSummary : cosObjectSummaries) {
                res.add(cosObjectSummary);
                // 文件的路径key
                String key = cosObjectSummary.getKey();
                log.info("文件的路径key: "+key);
                // 文件的etag
                String etag = cosObjectSummary.getETag();
                log.info("文件的路径etag: "+etag);
                // 文件的长度
                long fileSize = cosObjectSummary.getSize();
                log.info("文件的长度: "+fileSize);
                // 文件的存储类型
                String storageClasses = cosObjectSummary.getStorageClass();
                log.info("文件的存储类型: "+storageClasses);
            }

            String nextMarker = objectListing.getNextMarker();
            listObjectsRequest.setMarker(nextMarker);

        } while (objectListing.isTruncated());
        return res;
    }

    /**
     * <p>
     *     下载文件
     * </p>
     */
    public  static ObjectMetadata downLoadFile(String key,String localTargetFilePath)
    {
        GetObjectRequest getObjectRequest = new GetObjectRequest(BUCKETNAME, key);
        //下载文件到本地的路径，例如 D 盘的某个目录
        String outputFilePath = WINDOWS_FILE_STORAGE+localTargetFilePath;
        File downFile = new File(outputFilePath);
        getObjectRequest = new GetObjectRequest(BUCKETNAME, key);
        return  cosClient.getObject(getObjectRequest, downFile);
    }

    /**
     * <P>
     *     删除文件
     * </P>
     */
    public static void deleteFile(String key)
    {
        cosClient.deleteObject(BUCKETNAME, key);
    }

    static TransferManager createTransferManager() {
        // 自定义线程池大小，建议在客户端与 COS 网络充足（例如使用腾讯云的 CVM，同地域上传 COS）的情况下，设置成16或32即可，可较充分的利用网络资源
        // 对于使用公网传输且网络带宽质量不高的情况，建议减小该值，避免因网速过慢，造成请求超时。
        ExecutorService threadPool = Executors.newFixedThreadPool(32);
        // 传入一个 threadpool, 若不传入线程池，默认 TransferManager 中会生成一个单线程的线程池。
        TransferManager transferManager = new TransferManager(cosClient, threadPool);
        // 设置高级接口的配置项
        // 分块上传阈值和分块大小分别为 5MB 和 1MB
        TransferManagerConfiguration transferManagerConfiguration = new TransferManagerConfiguration();
        transferManagerConfiguration.setMultipartUploadThreshold(5*1024*1024);
        transferManagerConfiguration.setMinimumUploadPartSize(1*1024*1024);
        transferManager.setConfiguration(transferManagerConfiguration);
        return transferManager;
    }

}
